package me.zhengjie.minbearwcs.serivce.mission.processor.outbound;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.config.inf.WcsParamConfigDao;
import me.zhengjie.minbearwcs.dao.mission.inf.WcsMissionDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundDao;
import me.zhengjie.minbearwcs.dao.outbound.inf.OutboundTaskRecordDao;
import me.zhengjie.minbearwcs.dao.stock.inf.PalletDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.AgvActionSource;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.AgvTaskSource;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.actionEnum.AgvAction;
import me.zhengjie.minbearwcs.entity.DTO.transfer.Tuple;
import me.zhengjie.minbearwcs.entity.PO.agv.missionEnum.AgvMissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.WcsMission;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.status.OutboundSortMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.record.OutboundTaskRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.MediumStorageAndFloorNum;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.OutboundStockUpRecord;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.PalletSearchPo;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.type.StorageType;
import me.zhengjie.minbearwcs.resource.WcsResource;
import me.zhengjie.minbearwcs.serivce.agv.task.agvTask.AgvTaskDispatcher;
import me.zhengjie.minbearwcs.serivce.mission.generate.MissionGeneratorCollector;
import me.zhengjie.minbearwcs.serivce.mission.generate.type.MissionGenType;
import me.zhengjie.minbearwcs.serivce.mission.locker.StorageLockCollector;
import me.zhengjie.minbearwcs.serivce.mission.processor.MissionProcessor;
import me.zhengjie.minbearwcs.serivce.mission.processor.MissionProcessorCommonUtil;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor1.Storage1FLocker;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.OutboundStorage5Or6FloorLocker;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.Storage5Or6FloorPassSelector;
import me.zhengjie.minbearwcs.utils.IdWorker;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class OutboundSortMissionProcessor implements MissionProcessor {

    private final AgvTaskDispatcher getPutTaskDispatcher;
    private final TransactionTemplate transactionTemplate;
    private final WcsMissionDao wcsMissionDao;
    private final WcsResource wcsResource;
    private final IdWorker idWorker;
    private final MissionProcessorCommonUtil commonUtil;
    private final OutboundTaskRecordDao outboundTaskRecordDao;
    private final WcsParamConfigDao wcsParamConfigDao;
    private final Storage1FLocker storage1FLocker;
    private final SmallStorageDao smallStorageDao;
    private final OutboundDao outboundDao;
    private final StorageDao storageDao;
    private final PalletDao palletDao;
    private final OutboundStorage5Or6FloorLocker outboundStorage5Or6FloorLocker;
    private final MissionGeneratorCollector missionGeneratorCollector;
    private final Storage5Or6FloorPassSelector storage5Or6FloorPassSelector;

    private final Object lock = new Object();

    @Override
    public MissionType getMissionType() {
        return MissionType.OUTBOUND_SORT;
    }

    @Override
    public void process(WcsMission missionInfo) {
        OutboundSortMissionStatus missionStatus = (OutboundSortMissionStatus) missionInfo.getEnumMissionStatus();

        switch (missionStatus) {
            case WAIT_FOR_PALLET_STORAGE:
                searchPalletAndStorage(missionInfo);
                break;
            case SEARCHING_PALLET_STORAGE:
                break;
            case WAIT_FOR_DISPATCH:
                dispatchAgvTask(missionInfo);
                break;
            case DISPATCHING:
                break;
            case PROCESSING:
                monitorMission(missionInfo);
                break;
            case WAIT_FOR_SORT:
                break;
            case WAIT_FOR_DISPATCH_MANTISSA_AREA_5F_STORAGE:
                dispatchMantissaAreaAgvTask(missionInfo);
                break;
            case DISPATCHING_MANTISSA_AREA_5F_STORAGE:
                break;
            case PROCESSING_MANTISSA_AREA_5F_STORAGE:
                break;
            case WAIT_FOR_DISPATCH_EXCEPTION_AREA:
                dispatchExceptonAreaAgvTask(missionInfo);
                break;
            case DISPATCHING_EXCEPTION_AREA:
                break;
            case PROCESSING_EXCEPTION_AREA:
                break;
            case WAIT_FOR_CHECK_EXCEPTION:
                break;
            case WAIT_FOR_CONTINUE_SORT:
                dispatchContinueSortAgvTask(missionInfo);
                break;
            case DISPATCHING_CONTINUE_SORT:
                break;
            case PROCESSING_CONTINUE_SORT:
                break;
            case SORT_EXCEPTION:
                // 换板
                sortExceptionChangePallet(missionInfo);
                break;
            case FINISH:
                finishWcsMission(missionInfo);
                break;
            case CANCEL:
                break;
        }
    }


    public OutboundTaskRecord getOutboundTaskRecord(String recordId) {
        return outboundTaskRecordDao.selectByOutboundRecordId(recordId);
    }


    private void searchPalletAndStorage(WcsMission missionInfo) {
        boolean statusChangeSearchStorage = statusChangeSearchStorage(missionInfo.getId());
        if (!statusChangeSearchStorage) {
            return;
        }

        Boolean res = false;

        synchronized (StorageLockCollector.lockStorage5FOr6F) {
            synchronized (StorageLockCollector.lockRestStorage5FOr6F) {
                synchronized (StorageLockCollector.lockBeforeSortStorage5FOr6F) {


                    res = transactionTemplate.execute(status -> {
                        try {
                            OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());
                            // 1.找板
                            // 尾数区先找
                            boolean isFind = false;
                            PalletSearchPo palletSearchPo = outboundDao.selectCanSortPallet(
                                    outboundTaskRecord.getMaterialCode(),
                                    outboundTaskRecord.getMaterialNum(),
                                    StorageType.MANTISSA_AREA_5F
                            );
                            if (palletSearchPo != null) {
                                smallStorageDao.updateOutboundFreezeBySmallStorageCode(
                                        palletSearchPo.getSmallStorageCode(),
                                        palletSearchPo.getPalletCode()
                                );
                                outboundTaskRecord.setPalletCode(palletSearchPo.getPalletCode());
                                outboundTaskRecord.setStartFloorNum(5);
                                outboundTaskRecord.setStartSmallStorage(palletSearchPo.getSmallStorageCode());
                                outboundTaskRecord.setOriginalSmallStorage(palletSearchPo.getSmallStorageCode());
                                outboundTaskRecord.setOriginalPalletMaterialNum(palletSearchPo.getMaterialNum());
                                isFind = true;
                            } else {
                                List<MediumStorageAndFloorNum> canUseMediumStorageList = outboundDao.selectCanOutboundMediumSotrageNoNeedNum(
                                                outboundTaskRecord.getMaterialCode(),
                                                StorageType.STORAGE_AREA_5F,
                                                StorageType.STORAGE_AREA_6F
                                        )
                                        .stream()
                                        .distinct()
                                        .collect(Collectors.toList());

                                OutboundStockUpRecord outboundStockUpRecord = null;
                                for (MediumStorageAndFloorNum mediumCodeAndFloor : canUseMediumStorageList) {
                                    Tuple<OutboundStockUpRecord> outboundStockUpRecordTuple = outboundStorage5Or6FloorLocker.searchAndLockSortMedium(
                                            mediumCodeAndFloor.getMediumStorageCode(),
                                            mediumCodeAndFloor.getFloorNum(),
                                            outboundTaskRecord.getMaterialCode(),
                                            outboundTaskRecord.getMaterialNum()
                                    );
                                    if (outboundStockUpRecordTuple.success) {
                                        outboundStockUpRecord = outboundStockUpRecordTuple.value;
                                        isFind = true;
                                        break;
                                    }


                                    if (outboundDao.selectCanOutboundMediumSotrageNoNeedNum(
                                                    outboundTaskRecord.getMaterialCode(),
                                                    StorageType.STORAGE_AREA_5F,
                                                    StorageType.STORAGE_AREA_6F)
                                            .stream()
                                            .distinct()
                                            .collect(Collectors.toList())
                                            .isEmpty()) break;
                                }

                                if (isFind) {
                                    outboundTaskRecord.setPalletCode(outboundStockUpRecord.getPalletCode());
                                    outboundTaskRecord.setStartFloorNum(outboundStockUpRecord.getStartFloorNum());
                                    outboundTaskRecord.setStartSmallStorage(outboundStockUpRecord.getStartSmallStorage());
                                    outboundTaskRecord.setOriginalSmallStorage(outboundStockUpRecord.getStartSmallStorage());
                                    outboundTaskRecord.setOriginalPalletMaterialNum(outboundStockUpRecord.getMaterialNum());
                                }
                            }

                            // 2.储位
                            if (isFind) {
                                boolean hasDestination = false;
                                String destination = null;
                                int destinationFloor = 0;
                                if (outboundTaskRecord.getStartFloorNum() == 5) {
                                    destinationFloor = 5;
                                    destination = storageDao.selectNullStorageByStoargeType(StorageType.BEFORE_SORT_AREA_5F);
                                    hasDestination = destination != null;
                                } else if (outboundTaskRecord.getStartFloorNum() == 6) {
                                    destinationFloor = 6;
                                    destination = storageDao.selectNullStorageByStoargeType(StorageType.BEFORE_SORT_AREA_6F);
                                    hasDestination = destination != null;
                                }

                                if (hasDestination) {
                                    outboundTaskRecord.setDestinationFloorNum(destinationFloor);
                                    outboundTaskRecord.setDestinationSmallStorage(destination);
                                    outboundTaskRecordDao.update(outboundTaskRecord);
                                    return true;
                                } else {
                                    smallStorageDao.updateOutboundFreezeBySmallStorageCode(
                                            palletSearchPo.getSmallStorageCode(),
                                            null
                                    );
                                }

                            }

                            // 找不到，滚回
                            status.setRollbackOnly();
                            return false;

                        } catch (Exception e) {
                            log.error("wcs任务{}，1F储位锁定失败", missionInfo.getMissionId(), e);
                            status.setRollbackOnly();
                        }
                        return false;
                    });

                }
            }
        }

        if (Boolean.TRUE.equals(res)) {
            wcsMissionDao.updateMissionStatusById(
                    missionInfo.getId()
                    , OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name()
            );
        } else {
            wcsMissionDao.updateMissionStatusById(
                    missionInfo.getId()
                    , OutboundSortMissionStatus.WAIT_FOR_PALLET_STORAGE.name()
            );
        }


    }

    public boolean statusChangeSearchStorage(Integer missionId) {
        if (OutboundSortMissionStatus.WAIT_FOR_PALLET_STORAGE == wcsMissionDao.selectMissionStatusById(missionId)) {
            synchronized (lock) {
                if (OutboundSortMissionStatus.WAIT_FOR_PALLET_STORAGE == wcsMissionDao.selectMissionStatusById(missionId)) {
                    return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                        try {
                            wcsMissionDao.updateMissionStatusById(missionId, OutboundSortMissionStatus.SEARCHING_PALLET_STORAGE.name());
                            wcsMissionDao.updateStartTime(missionId, LocalDateTime.now());
                            return true;
                        } catch (Exception e) {
                            log.error("wcs任务状态转换出错", e);
                            status.setRollbackOnly();
                        }
                        return false;
                    }));
                }
            }
        }

        return false;
    }


    public boolean statusChangeDISPATCHING(Integer missionId) {
        if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH == wcsMissionDao.selectMissionStatusById(missionId)) {
            synchronized (lock) {
                if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH == wcsMissionDao.selectMissionStatusById(missionId)) {
                    return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                        try {
                            wcsMissionDao.updateMissionStatusById(missionId, OutboundSortMissionStatus.DISPATCHING.name());
                            return true;
                        } catch (Exception e) {
                            log.error("wcs任务状态转换出错", e);
                            status.setRollbackOnly();
                        }
                        return false;
                    }));
                }
            }
        }

        return false;
    }


    public void dispatchAgvTask(WcsMission missionInfo) {
        if (!statusChangeDISPATCHING(missionInfo.getId())) return;

        OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());


        wcsResource.getExecutor().execute(() -> {
            Boolean executeRes = transactionTemplate.execute(status -> {
                try {
                    Tuple<String> selectPass = storage5Or6FloorPassSelector.selectPass(outboundTaskRecord.getStartSmallStorage());

                    String agvTaskId = "Task_Agv_" + idWorker.nextId();
                    AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.OUTBOUND_TYPE, 1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                            OutboundSortMissionStatus.PROCESSING.name(), outboundTaskRecord.getPalletCode(),selectPass.value,null);
                    agvTaskSource.addAction(new AgvActionSource(outboundTaskRecord.getStartSmallStorage(), AgvAction.GET))
                            .addAction(new AgvActionSource(outboundTaskRecord.getDestinationSmallStorage(), AgvAction.PUT));


                    if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                        wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.PROCESSING.name());
                    } else {
                        wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name());
                    }
                    return true;
                } catch (Exception e) {
                    log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                    status.setRollbackOnly();
                }
                return false;
            });

            if (Boolean.FALSE.equals(executeRes)) {
                wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name());
            }

        });
    }


    public void monitorMission(WcsMission missionInfo) {

    }


    public boolean statusChangeDispatchingMantissa(Integer missionId) {
        if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH_MANTISSA_AREA_5F_STORAGE == wcsMissionDao.selectMissionStatusById(missionId)) {
            synchronized (lock) {
                if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH_MANTISSA_AREA_5F_STORAGE == wcsMissionDao.selectMissionStatusById(missionId)) {
                    return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                        try {
                            wcsMissionDao.updateMissionStatusById(missionId, OutboundSortMissionStatus.DISPATCHING_MANTISSA_AREA_5F_STORAGE.name());
                            return true;
                        } catch (Exception e) {
                            log.error("wcs任务状态转换出错", e);
                            status.setRollbackOnly();
                        }
                        return false;
                    }));
                }
            }
        }

        return false;

    }


    public void dispatchMantissaAreaAgvTask(WcsMission missionInfo) {
        if (!statusChangeDispatchingMantissa(missionInfo.getId())) return;

        OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());

        String resStorage = null;

        synchronized (StorageLockCollector.lockRestStorage5FOr6F) {

            resStorage = transactionTemplate.execute(status -> {
                try {
                    String nullSmallStorage = storageDao.selectNullStorageByStoargeType(StorageType.MANTISSA_AREA_5F);
                    if (nullSmallStorage == null) return null;
                    outboundStorage5Or6FloorLocker.lockDestinationStorage(nullSmallStorage, outboundTaskRecord.getPalletCode());
                    return nullSmallStorage;
                } catch (Exception e) {
                    log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                    status.setRollbackOnly();
                }
                return null;
            });

        }


        if (resStorage == null) {
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH_MANTISSA_AREA_5F_STORAGE.name());
            return;
        }

        String finalResStorage = resStorage;
        Boolean executeRes2 = transactionTemplate.execute(status -> {
            try {
                String agvTaskId = "Task_Agv_" + idWorker.nextId();
                AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.OUTBOUND_TYPE, 1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                        OutboundSortMissionStatus.PROCESSING_MANTISSA_AREA_5F_STORAGE.name(), outboundTaskRecord.getPalletCode(),null,null);
                agvTaskSource.addAction(new AgvActionSource(outboundTaskRecord.getDestinationSmallStorage(), AgvAction.GET))
                        .addAction(new AgvActionSource(finalResStorage, AgvAction.PUT));


                if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.PROCESSING.name());
                } else {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name());
                }
                return true;
            } catch (Exception e) {
                log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                status.setRollbackOnly();
            }
            return false;
        });

        if (Boolean.FALSE.equals(executeRes2)) {
            outboundStorage5Or6FloorLocker.lockDestinationStorage(resStorage, null);
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH_MANTISSA_AREA_5F_STORAGE.name());
        }
    }


    public boolean statusChangeDispatchingException(Integer missionId) {
        if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH_EXCEPTION_AREA == wcsMissionDao.selectMissionStatusById(missionId)) {
            synchronized (lock) {
                if (OutboundSortMissionStatus.WAIT_FOR_DISPATCH_EXCEPTION_AREA == wcsMissionDao.selectMissionStatusById(missionId)) {
                    return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                        try {
                            wcsMissionDao.updateMissionStatusById(missionId, OutboundSortMissionStatus.DISPATCHING_EXCEPTION_AREA.name());
                            return true;
                        } catch (Exception e) {
                            log.error("wcs任务状态转换出错", e);
                            status.setRollbackOnly();
                        }
                        return false;
                    }));
                }
            }
        }

        return false;

    }


    public void dispatchExceptonAreaAgvTask(WcsMission missionInfo) {
        if (!statusChangeDispatchingException(missionInfo.getId())) return;

        OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());

        String resStorage = null;

        Object exceptionAreaLock = null;
        StorageType exceptionStorageType = null;
        if (outboundTaskRecord.getDestinationFloorNum() == 5) {
            exceptionAreaLock = StorageLockCollector.lockExceptionArea5F;
            exceptionStorageType = StorageType.EXCEPTIONG_AREA_5F;
        } else {
            exceptionAreaLock = StorageLockCollector.lockExceptionArea6F;
            exceptionStorageType = StorageType.EXCEPTIONG_AREA_6F;
        }

        synchronized (exceptionAreaLock) {

            StorageType finalExceptionStorageType = exceptionStorageType;
            resStorage = transactionTemplate.execute(status -> {
                try {
                    String nullSmallStorage = storageDao.selectNullStorageByStoargeType(finalExceptionStorageType);
                    if (nullSmallStorage == null) return null;
                    outboundStorage5Or6FloorLocker.lockDestinationStorage(nullSmallStorage, outboundTaskRecord.getPalletCode());
                    return nullSmallStorage;
                } catch (Exception e) {
                    log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                    status.setRollbackOnly();
                }
                return null;
            });

        }


        if (resStorage == null) {
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH_EXCEPTION_AREA.name());
            return;
        }

        String finalResStorage = resStorage;
        Boolean executeRes2 = transactionTemplate.execute(status -> {
            try {
                String agvTaskId = "Task_Agv_" + idWorker.nextId();
                AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.OUTBOUND_TYPE, 1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                        OutboundSortMissionStatus.PROCESSING_EXCEPTION_AREA.name(), outboundTaskRecord.getPalletCode(),null,null);
                agvTaskSource.addAction(new AgvActionSource(outboundTaskRecord.getDestinationSmallStorage(), AgvAction.GET))
                        .addAction(new AgvActionSource(finalResStorage, AgvAction.PUT));


                if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.PROCESSING.name());
                } else {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name());
                }
                return true;
            } catch (Exception e) {
                log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                status.setRollbackOnly();
            }
            log.info("分拣栈板: {} 发生异常，将运送到异常区 ,outboundTaskRecord : {}",
                    outboundTaskRecord.getPalletCode(), outboundTaskRecord);

            return false;
        });

        if (Boolean.FALSE.equals(executeRes2)) {
            outboundStorage5Or6FloorLocker.lockDestinationStorage(resStorage, null);
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH_EXCEPTION_AREA.name());
        }
    }


    public boolean statusChangeDispatchingContinueSort(Integer missionId) {
        if (OutboundSortMissionStatus.WAIT_FOR_CONTINUE_SORT == wcsMissionDao.selectMissionStatusById(missionId)) {
            synchronized (lock) {
                if (OutboundSortMissionStatus.WAIT_FOR_CONTINUE_SORT == wcsMissionDao.selectMissionStatusById(missionId)) {
                    return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
                        try {
                            wcsMissionDao.updateMissionStatusById(missionId, OutboundSortMissionStatus.DISPATCHING_CONTINUE_SORT.name());
                            return true;
                        } catch (Exception e) {
                            log.error("wcs任务状态转换出错", e);
                            status.setRollbackOnly();
                        }
                        return false;
                    }));
                }
            }
        }

        return false;

    }


    public void dispatchContinueSortAgvTask(WcsMission missionInfo) {
        if (!statusChangeDispatchingContinueSort(missionInfo.getId())) return;

        OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());
        SmallStorage smallStorage = smallStorageDao.selectByPallet(outboundTaskRecord.getPalletCode());

        String resStorage = null;

        Object beforeSortAreaLock = null;
        StorageType beforeSortStorageType = null;
        if (outboundTaskRecord.getDestinationFloorNum() == 5) {
            beforeSortAreaLock = StorageLockCollector.lockExceptionArea5F;
            beforeSortStorageType = StorageType.BEFORE_SORT_AREA_5F;
        } else {
            beforeSortAreaLock = StorageLockCollector.lockExceptionArea6F;
            beforeSortStorageType = StorageType.BEFORE_SORT_AREA_6F;
        }

        synchronized (beforeSortAreaLock) {

            StorageType finalExceptionStorageType = beforeSortStorageType;
            resStorage = transactionTemplate.execute(status -> {
                try {
                    String nullSmallStorage = storageDao.selectNullStorageByStoargeType(finalExceptionStorageType);
                    if (nullSmallStorage == null) return null;
                    outboundStorage5Or6FloorLocker.lockDestinationStorage(nullSmallStorage, outboundTaskRecord.getPalletCode());
                    return nullSmallStorage;
                } catch (Exception e) {
                    log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                    status.setRollbackOnly();
                }
                return null;
            });

        }


        if (resStorage == null) {
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_CONTINUE_SORT.name());
            return;
        }

        String finalResStorage = resStorage;
        Boolean executeRes2 = transactionTemplate.execute(status -> {
            try {
                String agvTaskId = "Task_Agv_" + idWorker.nextId();
                AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.OUTBOUND_TYPE, 1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                        OutboundSortMissionStatus.PROCESSING_CONTINUE_SORT.name(), outboundTaskRecord.getPalletCode(),null,null);
                agvTaskSource.addAction(new AgvActionSource(smallStorage.getSmallStorageCode(), AgvAction.GET))
                        .addAction(new AgvActionSource(finalResStorage, AgvAction.PUT));


                if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.PROCESSING.name());
                } else {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_DISPATCH.name());
                }
                return true;
            } catch (Exception e) {
                log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId(), e);
                status.setRollbackOnly();
            }
            return false;
        });

        if (Boolean.FALSE.equals(executeRes2)) {
            outboundStorage5Or6FloorLocker.lockDestinationStorage(resStorage, null);
            wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_CONTINUE_SORT.name());
        }
    }


    private void sortExceptionChangePallet(WcsMission missionInfo) {
        AtomicReference<String> palletCode = new AtomicReference<>("");
        transactionTemplate.executeWithoutResult(status -> {
            try {
                OutboundTaskRecord outboundTaskRecord = getOutboundTaskRecord(missionInfo.getAssociatedDetailId());
                palletCode.set(outboundTaskRecord.getPalletCode());

                outboundTaskRecord.setPalletCode(null);
                outboundTaskRecord.setStartFloorNum(null);
                outboundTaskRecord.setStartSmallStorage(null);
                outboundTaskRecord.setOriginalSmallStorage(null);
                outboundTaskRecord.setOriginalPalletMaterialNum(null);
                outboundTaskRecord.setDestinationFloorNum(null);
                outboundTaskRecord.setDestinationSmallStorage(null);

                // update
                outboundTaskRecordDao.update(outboundTaskRecord);
                wcsMissionDao.updateMissionStatusById(missionInfo.getId(), OutboundSortMissionStatus.WAIT_FOR_PALLET_STORAGE.name());


                // 原栈板rollback
                missionGeneratorCollector.getGenerator(MissionGenType.OUTBOUND_SORT_EXCEPTION).generate(outboundTaskRecord);

                log.info("栈板 ：{} ，出现异常，将做换板处理", outboundTaskRecord.getPalletCode());
            } catch (Exception e) {
                status.setRollbackOnly();
                log.error("栈板 ：{} ，出现异常，换板处理失败", palletCode.get(), e);
            }
        });

    }


    public void finishWcsMission(WcsMission missionInfo) {
        transactionTemplate.executeWithoutResult(status -> {
            try {
//                OutboundStockUpRecord orderDetail = getOutboundStockUpDetail(missionInfo.getAssociatedDetailId());
//                if (orderDetail.getOutboundOrderCode() == null) {
//                    outboundStockUpRecordHistoryDao.insert(
//                            new OutboundStockUpRecordHistory(null, orderDetail.getStockUpId(), orderDetail.getOutboundOrderCode(), orderDetail.getOutboundOrderDetailId(),
//                                    orderDetail.getPalletCode(), orderDetail.getMaterialCode(), orderDetail.getMaterialNum(), orderDetail.getStartFloorNum(),
//                                    orderDetail.getStartSmallStorage(), orderDetail.getDestinationFloorNum(), orderDetail.getDestinationSmallStorage(), orderDetail.getCreateTime())
//                    );
//                    outboundTaskRecordDao.deleteById(orderDetail.getId());
//                }

                missionInfo.setFinishTime(LocalDateTime.now());
                commonUtil.transformMissionHistory(missionInfo);
            } catch (Exception e) {
                log.error("任务结束错误", e);
                status.setRollbackOnly();
            }
        });
    }
}
